﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Affinity.Flux
{
    /// <summary>
    /// Represents a component in the ComponentModel system.
    /// </summary>
    internal class Component
    {
        /// <summary>
        /// Constructor accepting the component this object will represent.
        /// </summary>
        /// <param name="instance"></param>
        public Component(object instance)
        {
            if (instance == null) throw new ArgumentNullException("instance");
            _instance = instance;
            TypeInfo typeInfo = _typeInfoCollection.GetOrCreateTypeInfo(instance.GetType());

            _inlets = typeInfo.InletDefinitions.Select(inletDefinition => Inlet.Create(inletDefinition, instance)).ToArray();
            _outlets = typeInfo.OutletDefinitions.Select(outletDefinition => Outlet.Create(outletDefinition, instance)).ToArray();
            _childReferences = typeInfo.ChildReferenceDefinitions.Select(childReferenceDefinition => ChildReference.Create(childReferenceDefinition, instance)).ToArray();
        }

        /// <summary>
        /// Gets the child references exposed by this component.
        /// </summary>
        public ChildReference[] ChildReferences
        {
            get { return _childReferences; }
        }
        private readonly ChildReference[] _childReferences;

        /// <summary>
        /// Gets the inlets exposed by this component.
        /// </summary>
        public Inlet[] Inlets
        {
            get { return _inlets; }
        }
        private readonly Inlet[] _inlets;

        /// <summary>
        /// Gets the component instance represented by this instance of Component.
        /// </summary>
        public object Instance
        {
            get { return _instance; }
        }

        /// <summary>
        /// Gets the outlets exposed by this component.
        /// </summary>
        public Outlet[] Outlets
        {
            get { return _outlets; }
        }
        private readonly Outlet[] _outlets;

        /// <summary>
        /// Decrements the reference count.
        /// </summary>
        /// <returns>The new reference count.</returns>
        public int DecrementReferenceCount()
        {
            return --_referenceCount;
        }

        /// <summary>
        /// Increments the reference count.
        /// </summary>
        /// <returns>The new reference count.</returns>
        public int IncrementReferenceCount()
        {
            return ++_referenceCount;
        }

        private readonly object _instance;
        private volatile int _referenceCount;
        private static readonly TypeInfoCollection _typeInfoCollection = new TypeInfoCollection();
    }
}
